#include "sfsis.h"
#include "gd32f1x0.h"
#include "systick.h"
#include "debug.h"
#include "soft_iic.h"
#define SPI_TIMEOUT 1

void hwl_init(void)
{
    //iic外设初始化，主要用于EEPROM
    hwl_iic_init();
    //spi 外设初始化，主要用于LT8920
    hwl_spi_init();
    //DMA_SPI初始化，主要用于WS2812
    hwl_dma_spi_init();
    /*ADC 初始化，主要用于模拟值按键*/
    hwl_adc_init();
    //LED初始化
    hwl_gpio_set(HWL_PIN_LED1, HWL_OUTPUT);
}

/*GPIO*/
void hwl_gpio_set(HWL_GpioUsed hwl_gpio, HWL_GpioState value) //sf true high sf false low
{
    if (value == HWL_INPUT)
    {
        switch (hwl_gpio)
        {
        case HWL_PIN_LT8920_RST:
            rcu_periph_clock_enable(RCU_GPIOA); //启动clockA时钟线
            gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
            break;
        case HWL_PIN_LT8920_PKT:
            rcu_periph_clock_enable(RCU_GPIOA); //启动clockA时钟线
            gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
            break;
        case HWL_PIN_LED1:
            rcu_periph_clock_enable(RCU_GPIOA); //启动clockA时钟线
            gpio_mode_set(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_13);
            break;
        default:
            break;
        }
    }
    else if (value == HWL_OUTPUT)
    {
        switch (hwl_gpio)
        {
        case HWL_PIN_LT8920_RST:
            //LT8920 RST GPIO PIN 2 output
            rcu_periph_clock_enable(RCU_GPIOA); //启动clockA时钟线
            gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
            gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
            break;
        case HWL_PIN_LT8920_PKT:
            //LT8920 RST GPIO PIN 2 output
            rcu_periph_clock_enable(RCU_GPIOA); //启动clockA时钟线
            gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
            gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
            break;
        case HWL_PIN_LED1:
            rcu_periph_clock_enable(RCU_GPIOA); //启动clockA时钟线
            gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_13);
            gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
            break;

        default:
            break;
        }
    }
    else
    {
        switch (hwl_gpio)
        {
        case HWL_PIN_LT8920_RST:
            /*复位LT8920 GPIO使用*/
            if (value == HWL_LOW)
            {
                GPIO_BC(GPIOA) = GPIO_PIN_2;
            }
            else if (value == HWL_HIGH)
            {
                GPIO_BOP(GPIOA) = GPIO_PIN_2;
            }
            break;
        case HWL_PIN_LT8920_PKT:
            //PKT 脚不支持输出，啥都不干
            /*复位LT8920 GPIO使用*/
            if (value == HWL_LOW)
            {
                GPIO_BC(GPIOA) = GPIO_PIN_3;
            }
            else if (value == HWL_HIGH)
            {
                GPIO_BOP(GPIOA) = GPIO_PIN_3;
            }
            break;
        case HWL_PIN_LED1: //LED灯控制口
            if (value == HWL_LOW)
            {
                GPIO_BC(GPIOA) = GPIO_PIN_13;
            }
            else if (value == HWL_HIGH)
            {
                GPIO_BOP(GPIOA) = GPIO_PIN_13;
            }
            break;
        default:
            break;
        }
    }
}

HWL_GpioState hwl_gpio_get(HWL_GpioUsed hwl_gpio)
{
    HWL_GpioState ret = HWL_LOW;
    switch (hwl_gpio)
    {
    case HWL_PIN_LT8920_PKT:
        if (gpio_input_bit_get(GPIOA, GPIO_PIN_3) == SET)
        {
            ret = HWL_HIGH;
        }
        else
        {
            ret = HWL_LOW;
        }
        break;

    default:
        break;
    }
    return ret;
}

/*spi初始化，服务于lt8920*/
void hwl_spi_init(void)
{
    spi_parameter_struct spi_init_struct;
    //使能SPI模块的时钟
    rcu_periph_clock_enable(RCU_SPI0);
    //设置GPIO为SPI0的接口
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_af_set(GPIOA, GPIO_AF_0, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);

    //配置SPI参数
    spi_i2s_deinit(SPI0);
    spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; //全双工
    spi_init_struct.device_mode = SPI_MASTER;
    spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE; //和LT8920相关
    spi_init_struct.nss = SPI_NSS_SOFT;                            //软件定义SS
    spi_init_struct.prescale = SPI_PSC_32;                         //set to 2Mhz Clock = 64Mhz/32 = 2Mhz
    spi_init_struct.endian = SPI_ENDIAN_MSB;

    spi_init(SPI0, &spi_init_struct);
    spi_enable(SPI0);

    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
    GPIO_BOP(GPIOA) = GPIO_PIN_4;
}

void hwl_spi_SS_set(void)
{
    GPIO_BOP(GPIOA) = GPIO_PIN_4;
}

void hwl_spi_SS_reset(void)
{
    GPIO_BC(GPIOA) = GPIO_PIN_4;
}

SF_Boolen hwl_spi_TxMultByte(su8 *txBuf, su16 count)
{
    uint16_t n = 0;
    for (n = 0; n < count; n++)
    {
        spi_i2s_data_transmit(SPI0, txBuf[n]);
        while (RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE))
        {
        }
        while (RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE))
        {
        }
        spi_i2s_data_receive(SPI0);
    }

    return SF_True;
}

SF_Boolen hwl_spi_RxMultByte(su8 *rxBuf, su16 count)
{
    uint16_t n = 0;
    for (n = 0; n < count; n++)
    {
        spi_i2s_data_transmit(SPI0, 0xFF);
        while (RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE))
        {
        }

        while (RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE))
        {
        }
        rxBuf[n] = spi_i2s_data_receive(SPI0);
    }
    return SF_True;
}

/*iic接口 用于eeprom 调用soft_iic，具体实现在soft_iic*/
//默认硬件的device 地址，在sf中，没有必要特别高的读取效率
#define HWL_EEPROM_DEVICE_ADDRESS 0xA0
void hwl_iic_init(void)
{
    static SF_Boolen isInited = SF_False;
    if (isInited == SF_False)
    {
        isInited = SF_True;
        soft_iic_init();
    }
}

void hwl_iic_reset(void)
{

    su16 i = 0;
    su16 d;
    for (d = 0; d < 32; d++)
    {
        soft_iic_start();
        soft_iic_writeByte(HWL_EEPROM_DEVICE_ADDRESS);
        if (soft_iic_wait_ack())
        {
            DPRINT(DEBUG_INFO, "[EEPROM] write Register wait ack\r\n");
            return;
        }
        soft_iic_writeByte(d * 8);
        if (soft_iic_wait_ack())
        {
            DPRINT(DEBUG_INFO, "[EEPROM] write Register address ERROR!\r\n");
            return;
        }
        for (i = 0; i < 8; i++)
        {
            soft_iic_writeByte(0xFF);
            if (soft_iic_wait_ack())
            {
                DPRINT(DEBUG_INFO, "[EEPROM] address 0x%d ERROR!\r\n", i);
                return;
            }
        }
        soft_iic_stop();
        hwl_delay_ms(5);
    }
}
void i_hwl_iic_write(su8 address, su8 *buf, su16 buflen)
{
    su16 i = 0;
    soft_iic_start();
    soft_iic_writeByte(HWL_EEPROM_DEVICE_ADDRESS);
    if (soft_iic_wait_ack())
    {
        DPRINT(DEBUG_ERROR, "[EEPROM] write address ERROR! Address:%d\r\n", address);
        return;
    }
    soft_iic_writeByte(address);
    if (soft_iic_wait_ack())
    {
        DPRINT(DEBUG_ERROR, "[EEPROM] write Register address ERROR!\r\n");
        return;
    }
    for (i = 0; i < buflen; i++)
    {
        soft_iic_writeByte(buf[i]);
        if (soft_iic_wait_ack())
        {
            DPRINT(DEBUG_ERROR, "[EEPROM] address 0x%d ERROR!\r\n", i);
            return;
        }
    }
    soft_iic_stop();
    hwl_delay_ms(5);
}
void hwl_iic_write(su8 address, su8 *buf, su16 buflen)
{
    su16 block = 0;
    su16 tt = 0;
    block = buflen / 16;

    for (tt = 0; tt < block; tt++)
    {
        i_hwl_iic_write(address + tt * 16, buf + tt * 16, 16);
        hwl_delay_ms(5);
    }
    i_hwl_iic_write(address + tt * 16, buf + tt * 16, buflen % 16);
}

void hwl_iic_read(su8 address, su8 *buf, su16 readLen)
{
    su16 ii = 0;
    soft_iic_start();
    soft_iic_writeByte(HWL_EEPROM_DEVICE_ADDRESS);
    if (soft_iic_wait_ack())
    {
        return;
    }
    soft_iic_writeByte(address);
    if (soft_iic_wait_ack())
    {
        return;
    }
    soft_iic_start();
    soft_iic_writeByte(HWL_EEPROM_DEVICE_ADDRESS | 0x01);
    if (soft_iic_wait_ack())
    {
        return;
    }
    for (ii = 0; ii < readLen - 1; ii++)
    {
        buf[ii] = soft_iic_readByte(0);
        hwl_delay_us(16);
    }
    buf[ii] = soft_iic_readByte(1);
    soft_iic_stop();
}

su8 hwl_iic_readReg(su8 address)
{
    su8 buf[1];
    buf[0] = 0xFF;
    hwl_iic_read(address, buf, 1);
    return buf[0];
}

void hwl_iic_writeReg(su8 address, su8 value)
{
    su8 buf[1];
    buf[0] = value;
    hwl_iic_write(address, buf, 1);
}

/*spi接口,服务于ws2812*/
void hwl_dma_spi_init(void)
{
    dma_parameter_struct dma_init_struct;
    spi_parameter_struct spi_init_struct;
    //step1: spi dma clock and gpio init
    //1.ebable periph clock
    rcu_periph_clock_enable(RCU_SPI1);
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_DMA);
    //spi1 gpio config gpioa 14 mosi transmitter only,clock and miso not needed. just for ws2812
    gpio_af_set(GPIOA, GPIO_AF_6, GPIO_PIN_14);
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);

    //step2: dma channel init
    dma_deinit(DMA_CH4);
    dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI1);  //SPI1-CH4
    dma_init_struct.periph_inc = DMA_MEMORY_INCREASE_DISABLE; //外设地址增长关闭
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; //宽度8bit
    dma_init_struct.memory_addr = NULL;                       //
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 0;
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH4, &dma_init_struct);

    //step3: spi config
    spi_init_struct.trans_mode = SPI_BIDIRECTIONAL_TRANSMIT;
    spi_init_struct.device_mode = SPI_MASTER;
    spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
    spi_init_struct.nss = SPI_NSS_SOFT;
    spi_init_struct.prescale = SPI_PSC_16;
    spi_init_struct.endian = SPI_ENDIAN_MSB;
    spi_init(SPI1, &spi_init_struct);
    spi_enable(SPI1);
}

/*dma spi*/
void hwl_dma_spi_transfer(void *buffer, su16 bufLen)
{
    dma_channel_disable(DMA_CH4);
    dma_memory_address_config(DMA_CH4, (uint32_t)buffer);
    dma_transfer_number_config(DMA_CH4, bufLen);
    dma_channel_enable(DMA_CH4);
    spi_dma_enable(SPI1, SPI_DMA_TRANSMIT);
}

/*ADC端口初始化，主要用于服务ADkey*/
void hwl_adc_init(void)
{
    //开时钟
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_ADC);
    rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6);
    //设置引脚
    gpio_mode_set(GPIOB, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);

    /* ADC contineous function enable */
    adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);
    /* ADC trigger config */
    adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
    /* ADC channel length config */
    adc_channel_length_config(ADC_REGULAR_CHANNEL, 1);

    /* ADC regular channel config */
    adc_regular_channel_config(0, ADC_CHANNEL_9, ADC_SAMPLETIME_55POINT5);
    adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
    adc_enable();
    hwl_delay_ms(1);
    /* ADC calibration and reset calibration */
    adc_calibration_enable();
    adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
}

void hwl_adc_start(void)
{
    adc_flag_clear(ADC_FLAG_EOC);
}

SF_Boolen hwl_adc_isConvertFinished(void)
{
    if (SET == adc_flag_get(ADC_FLAG_EOC))
    {
        return SF_True;
    }
    else
    {
        return SF_False;
    }
}

su16 hwl_adc_getValue(void)
{
    return (su16)ADC_RDATA;
}

SF_Boolen hwl_dma_spi_isTransferBusy(void)
{
    if (spi_i2s_flag_get(SPI1, SPI_FLAG_TRANS) == SET)
    {
        return SF_True;
    }
    else
    {
        return SF_False;
    }
}

/*延时函数*/
void hwl_delay_us(su16 us)
{
    volatile unsigned char tt;
    while (us--)
    {
        tt = 6;
        while (tt--)
        {
        }
    }
}

void hwl_delay_ms(su16 ms)
{
    delay_1ms(ms);
}
